package com.timing.finder.framework;

import com.timing.finder.util.DateUtils;

import java.text.ParseException;
import java.util.*;

/**
 * @author JingGe(* ^ ▽ ^ *)
 * @date 2023-03-08 15:36
 * @email 1158055613@qq.com
 */
public class TimeSeriesDataFinder<T extends TimeSeriesData> {
    private final CacheRepository repository;
    private final long startOffset;
    private final long unitOffset;


    TimeSeriesDataFinder(TimeSeriesDataHandler<T> handler) {
        this.repository = handler.cacheRepository();
        startOffset = handler.startOffset();
        unitOffset = handler.unitOffset();
    }

    /**
     * 创建一个查找器实例
     *
     * @param configSuffix 时序数据库相关配置的后缀名
     * @author JingGe(* ^ ▽ ^ *)
     * @date 2023/6/20 16:53
     */
    public TimeSeriesDataFinder(String configSuffix) {
        TimingFinderConfig config = new YamlConfigFactory().create(configSuffix);
        ProtoStuffSerializerAndDeserializer codec = new ProtoStuffSerializerAndDeserializer();
        this.repository = new RedisRepository(codec, codec, config);
        startOffset = config.defaultStartOffset;
        unitOffset = config.defaultUnitOffset;
    }

    public <R extends CacheData> R index(String key, String dateString, Class<R> type, boolean needFormat) {
        try {
            return index(key, parseDateString(dateString).getTime(), needFormat, type);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    public <R extends CacheData> Map<String, R> indexPattern(String pattern, String dateString, Class<R> type) {
        Set<String> keys = repository.scanPatternKeys(pattern);
        if (keys == null || keys.size() == 0) {
            return Collections.emptyMap();
        }
        Map<String, R> res = new HashMap<>();
        for (String key : keys) {
            res.put(key, index(key, dateString, type, false));
        }
        return res;
    }

    private String formatKey(String key) {
        return repository.formatKey(key);
    }

    private Date parseDateString(String dateString) throws ParseException {
        return DateUtils.parseDate(dateString, "yyyyMMdd", "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss");
    }

    public <R extends CacheData> R index(String key, long timestamp, boolean needFormat, Class<R> type) {
        return repository.index(needFormat ? formatKey(key) : key, offset(timestamp), type);
    }


    public <R extends CacheData> List<R> range(String key, long start, long end, boolean needFormat, Class<R> type) {
        return repository.range(needFormat ? formatKey(key) : key, offset(start), offset(end), type);
    }

    public <R extends CacheData> List<R> range(String key, String startString, String endString, boolean needFormat, Class<R> type) {
        try {
            return range(key, parseDateString(startString).getTime(), parseDateString(endString).getTime(), needFormat, type);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    public <R extends CacheData> Map<String, List<R>> rangePattern(String pattern, String startString, String endString, Class<R> type) {
        Set<String> keys = repository.scanPatternKeys(pattern);
        if (keys == null || keys.size() == 0) {
            return Collections.emptyMap();
        }
        Map<String, List<R>> res = new HashMap<>();

        for (String key : keys) {
            res.put(key, range(key, startString, endString, false, type));
        }
        return res;
    }

    private long offset(long timestamp) {
        return ((timestamp - startOffset) / unitOffset) + 1;
    }

}
